#include "StdAfx.h"
#include "Circuit.h"
#include "Utility.h"
#include "Gate.h"
#include "AND.h"
#include "NAND.h"
#include "NOR.h"
#include "OR.h"
#include "XOR.h"
#include "Reader.h"
#include "factory.h"
#include <typeinfo>

Utility *Utility::instance = 0;

Circuit::~Circuit(void)
{
}

//bouwt het circuit op aan de hand van de totale input
Circuit::Circuit(char* path)//circuitAsString)
{

	Reader* reader = new Reader();
	string circuitAsString = reader->readFileToString(path);
	bool isError = false;

	vector<string> lines = Utility::getInstance()->split(circuitAsString, '\n');
	hash_map<string, Node *> nodes;

	bool nodeParsing = false;
	bool edgeParsing = false;
	char charsToRemove[] = " ;\t";
	for(int i = 0; i < lines.size(); i++)
	{
		if(nodeParsing || (Utility::getInstance()->startsWith(lines[i],"#") && Utility::getInstance()->endsWith(lines[i],"nodes")))
		{
			nodeParsing = true;
			while(Utility::getInstance()->startsWith(lines[i],"#")){
				i++;
			}

			while(!Utility::getInstance()->startsWith(lines[i],"#")){
				Utility::getInstance()->removeChars(lines[i],charsToRemove); //verwijdert de spaties en ; op het einde
				vector<string> nameAndInput = Utility::getInstance()->split(lines[i],':'); //splitst het op in 2 delen

				if(nameAndInput.size() == 2){
					Node* node = factory::create(nameAndInput[1]);
					if(node != NULL)
					{
						nodes[nameAndInput[0]] = node;
						if(Utility::getInstance()->contains(lines[i],"INPUT_HIGH") || Utility::getInstance()->contains(lines[i],"INPUT_LOW")) //input componenten
						{
							this->AddInput((StartNode*)node);
						}
						else if(Utility::getInstance()->contains(lines[i],"PROBE")) //output componenten
						{
							((EndNode*)node)->SetCircuit(this);
							this->AddOutput((EndNode*)node);

						}
						else if(Utility::getInstance()->startsWith(lines[i],"NODE")) //node componenten
						{
							this->nodes.push_back(nodes[nameAndInput[0]]);
						}
					}
					else
					{
						cout << "ERROR parsing : '" << nameAndInput[1] << "', aborting!" << endl;
						isError = true;
						break;break;
					}
					//cout << "line: " << lines[i]  << endl;
				} //if(nameAndInput.size() == 2){
				i++;
			} // while loop
			
			cout << "nodes size: " << nodes.size() << endl;

			if(Utility::getInstance()->startsWith(lines[i],"#")){
				nodeParsing = false;
				cout << endl;
			}
		} else if(edgeParsing || (Utility::getInstance()->startsWith(lines[i],"#") && Utility::getInstance()->endsWith(lines[i],"edges")))
		{
			edgeParsing = true;
			while(Utility::getInstance()->startsWith(lines[i],"#")){
				i++;
			}

			while(!((i) == lines.size())){
				Utility::getInstance()->removeChars(lines[i],charsToRemove); //verwijdert de spaties en ; op het einde
				vector<string> nameAndInput = Utility::getInstance()->split(lines[i],':'); //splitst het op in 2 delen
				
				if(nameAndInput.size() == 2){
					vector<string> gatesToAssign = Utility::getInstance()->split(nameAndInput[1],','); //splitst de overige delen op
					//cout << "nameAndInput size: " << nameAndInput[1] << " - " << gatesToAssign.size() << endl;

					if (nodes.find(nameAndInput[0]) == nodes.end())
					{ /* Not found */
						cout << "ERROR not found : '" << nameAndInput[0] << "', aborting!" << endl;
						isError = true;
						break;break;break;
					} else { /* Found, i->first is f, i->second is ++-- */
						//nodes[nameAndInput[0]]
					}

					for (int i = 0; i < gatesToAssign.size(); i++)
					{
						if (nodes.find(gatesToAssign[i]) == nodes.end())
						{ /* Not found */
							cout << "ERROR not found : '" << gatesToAssign[i] << "', aborting!" << endl;
							isError = true;
							break;break;break;
						} else { /* Found, i->first is f, i->second is ++-- */

							nodes[nameAndInput[0]]->LinkOutputWith(nodes[gatesToAssign[i]]->GetInputForLink());
						}
					}
						
					//cout << "line: " << ""<< endl;
				}

				i++;
			}
		}

		//cout << "line: " << lines[i]  << endl;
	} // end for(int i = 0; i < lines.size(); i++)

	if(isError){ //EROOR occured
		cout << "One or multiple errors occured, cannot start circuit! Please check input!" << endl;
	} //end ELSE if(isError){ //EROOR occured
}

void Circuit::notify()
{
	int count = 0;
	int total = outputs.size();
	for(int i = 0; i < outputs.size(); i++)
	{
		if(outputs[i]->IsSet())
		{
			count++;
		}
	}
	if(count == total)
	{
		stringstream total;
		cout << "Output: ";
		for(int i = 0; i < outputs.size(); i++)
		{
			cout << outputs[i]->GetValue() << " ";
		}
		cout << endl;
	}
}

void Circuit::Simulate(void)
{
	for(int i = 0; i < this->inputs.size(); i++)
	{
		this->inputs[i]->notify();
	}

	//checkt of het circuit wel helemaal doorlopen is
	int count = 0;
	int total = outputs.capacity();
	for(int i = 0; i < outputs.capacity(); i++)
	{
		if(outputs[i]->IsSet())
		{
			count++;
		}
	}
	if(count != total)
	{
		cout << "ERROR - Circuit not fully completed! Hangs somewhere!" << endl;
	}
}
void Circuit::AddInput(StartNode* node)
{
	this->inputs.push_back(node);
}

void Circuit::AddOutput(EndNode* node)
{
	this->outputs.push_back(node);
}

